#ifndef __L0032_0_DATAXCHGTABLE_H__
#define __L0032_0_DATAXCHGTABLE_H__

#include "xtable.h"

// typedef uint32_t entry_handle;

#define L0032_DXTABLE_NAME						"L0032_DXTABLE"
#define L0032_INDEX2HANDLE(HENTRY_INDEX)	((HENTRY_INDEX) ^ 0xDEAD8EEF)
#define L0032_HANDLE2INDEX(HENTRY)			((HENTRY) ^ 0xDEAD8EEF)
#define INVALID_ENTRY_HANDLE				(entry_handle)0xFFFFFFFF

#define L0032_DXTABLE_FLAGS_UNASSIGNED			0x0
#define L0032_DXTABLE_FLAGS_DATAI8TABLE			0x1
#define L0032_DXTABLE_FLAGS_DATAU8TABLE			0x2
#define L0032_DXTABLE_FLAGS_DATAI32TABLE		0x4
#define L0032_DXTABLE_FLAGS_DATAU32TABLE		0x8
#define L0032_DXTABLE_FLAGS_DATAF32TABLE		0x10
#define L0032_DXTABLE_FLAGS_DATAF64TABLE		0x20
#define L0032_DXTABLE_FLAGS_DATAU64TABLE		0x40
#define L0032_DXTABLE_FLAGS_DATAI64TABLE		0x80
#define L0032_DXTABLE_FLAGS_DATABUFTABLE		0x100		//data buffer block
#define L0032_DXTABLE_FLAGS_IPC					0x1000		//inter-process communication

#define L0032_DXTABLE_ENTRYMAX				256
#define L0032_DXTABLE_ENTRYNAME_MAX			32
#define L0032_DXTABLE_MSGMAX				32
#define L0032_DXTABLE_POINTMAX				(1 * 1024 * 1024)  // 1M

#define L0032_DXTABLE_METADATA_SIZE			(sizeof(struct l0032_dataxchgtable))
#define L0032_DXTABLE_DEFAULT_SIZE			(L0032_DXTABLE_METADATA_SIZE + L0032_DXTABLE_POINTMAX)		

#define L0032_DXTABLE_FLAGS_CREATOR			1
#define L0032_DXTABLE_FLAGS_READY			2

#define L0032_ISDXTABLE_READY(DXTABLE)				((DXTABLE != NULL) && (DXTABLE)->flags & L0032_DXTABLE_FLAGS_READY)

#define L0032_DXTABLE_ERRNO_NOERROR		0
#define L0032_DXTABLE_ERRNO_UNKNOWN		-1
#define L0032_DXTABLE_ERRNO_OOM			-2
#define L0032_DXTABLE_ERRNO_EXIST		-3
#define L0032_DXTABLE_ERRNO_SIZE		-4

/*
 * offset is uint32_t type that limits the size of the data exchange table to less than 4GB.
 * In case of access shared memory out of control, let's playing little tricks returning handler to user.
 */
struct l0032_dataxchgtable_entry {
	uint8_t name[L0032_DXTABLE_ENTRYNAME_MAX];
	pthread_mutex_t lock;	// lock for read/write on the data section of this entry
	uint32_t offset;		// offset from dxtable base address
	size_t npoints;
	size_t pointsz;
	uint32_t flags;
	/*
	 * use 'next' to link all the same type of data section together. 'next' is index of the entry
	 */
	uint32_t next;
}__attribute__((packed));

#if L0032_CONFIG_MSG_ENABLE
struct l0032_dataxchgtable_message {
}__attribute__((packed));
#endif
/*
|----------------------------|
|          entry0            |
|----------------------------|
|          entry1			 |
|----------------------------|------>metadata area
|          entry2			 |
|----------------------------|
|          entryn			 |
|----------------------------|
|                            |
|           data             |------>point data area
|                            |
|----------------------------|
 */

struct l0032_dataxchgtable {
	size_t sz;
	pthread_mutex_t lock;		// lock for new an entry
	struct l0032_dataxchgtable_entry entry[L0032_DXTABLE_ENTRYMAX];
	uint32_t nentries;			//num of assigned entries
#if L0032_CONFIG_MSG_ENABLE
	struct l0032_dataxchgtable_message msg[L0032_DXTABLE_MSGMAX];
	uint32_t nmsgs;
#endif
	uint32_t offset_data;		//the offset of the unassigned memory region
	uint32_t end;
}__attribute__((packed));


int l0032_dataxchgtable_open(const char* shmname, size_t *sz, int bCreate);
void l0032_dataxchgtable_close(void);
int l0032_entry_read(entry_handle hentry, int pointno, void* addr, size_t sz);
int l0032_entry_write(entry_handle hentry, int pointno, void* addr);

entry_handle l0032_dataxchgtable_index2handle(int entry_index);
int l0032_dataxchgtable_handle2index(entry_handle hentry);

const char* l0032_typestring(int type);
size_t l0032_typesize(int type);
int l0032_is_valid_entryhandle(entry_handle hentry);
entry_handle l0032_nextentry(entry_handle hentry);
entry_handle l0032_get_entry(const char* name);
uint32_t l0032_get_nentries(void);
const char* l0032_entry_get_name(entry_handle hentry);
int l0032_entry_get_npoints(entry_handle hentry);
int l0032_entry_get_pointsz(entry_handle hentry);
int l0032_entry_get_offset(entry_handle hentry, uint32_t *offset);
int l0032_entry_get_pointtype(entry_handle hentry);
size_t l0032_entry_get_size(entry_handle hentry);
int l0032_entry_get_address(entry_handle hentry, uint8_t **pcache, size_t *sz);

int l0032_dataxchgtable_rawcopy(uint8_t **paddr, size_t *sz, uint32_t from);
int l0032_dataxchgtable_metadata(uint8_t **paddr, size_t *sz);
int l0032_entry_readpoints(entry_handle hentry, int point_from, int *npoints, uint8_t *cache, size_t sz);
int l0032_entry_writepoints(entry_handle hentry, int point_from, int* npoints, uint8_t *val);
entry_handle l0032_entry_allocate_buffer(const char* name, size_t sz, int *dxterrno);
entry_handle l0032_entry_allocate(const char* name, int type, size_t npoints, int *dxterrno);

/*
 * resource lock
 */
void l0032_dataxchgtable_lock(void);
void l0032_dataxchgtable_unlock(void);
void l0032_entry_lock(entry_handle hentry);
void l0032_entry_unlock(entry_handle hentry);
#endif
